#! /bin/sh -
#
# Boot-time system initialization script
#
# Copyright (c) 2017-2018 Matias Fonzo.
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Parse config file

if test -f /etc/rc.conf
then
    while IFS='=' read -r variable value
    do
        case $variable in
        \#* | "")	# Ignore commented or blank lines
            continue
            ;;
        esac

        # Set variable name avoiding code execution
        eval "$variable=\${value}"
    done < /etc/rc.conf
fi

umask 022
IFS='
 	'
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin
export PATH

# Make the kernel send the SIGINT (interrupt) signal to the init process
ctrlaltdel soft

# Mount virtual file systems

echo "(Startup): Mounting kernel based file systems"
mount -v -n -o nosuid,noexec,nodev -t proc proc /proc
mount -v -n -o nosuid,noexec,nodev -t sysfs sysfs /sys
if ! mountpoint -q /dev
then
    mount -v -n -t devtmpfs devtmpfs /dev
else
    # Re-mount devtmpfs if necessary due to an initramfs
    mount -v -n -o remount -t devtmpfs devtmpfs /dev
fi

mkdir -p /dev/pts /dev/shm
mount -v -n -o mode=0620,gid=5 -t devpts devpts /dev/pts
mount -v -n -o defaults -t tmpfs none /dev/shm
mount -v -n -o defaults -t tmpfs tmpfs /run

# Start the dynamic device management

echo "(Startup) Starting event managing daemon"
udevd --daemon

# Request device uevents to replay events at system coldplug
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices    --action=add

# Wait for event queue
udevadm settle

# Remount the root filesystem in *read-only mode*, if needed
if test -w /
then
    echo "(Startup) Remounting root filesystem in read-only mode"
    mount -v -n -o remount,ro /
fi

# Mount Control Groups (v1)

if grep -q cgroup /proc/filesystems
then
    if test -d /sys/fs/cgroup
    then
        # Cgroup controllers v1 must be mounted against a tmpfs(5)
        mount -v -n -t tmpfs cgroup_root /sys/fs/cgroup

        # Comount all v1 controllers against the same hierarchy
        mount -v -n -t cgroup cgroup /sys/fs/cgroup
    fi
fi

# Initialize the Logical Volume Manager version 2

if type lvm > /dev/null 2>&1
then
    echo "(LVM2) Scanning for new volume groups ..."
    vgscan --mknodes --ignorelockingfailure 2> /dev/null && \
     vgchange --ignorelockingfailure -a y
fi

# Activate swap partition if any available
swapon -a

# Set system clock (1/2)

# Avoid unnecessary fsck runs at boot time, especially for
# already existing (multiple) systems not designed for UTC
hwclock --hctosys --localtime

# Perform file system checks

# Force file system checks if 'FORCEFSCK' was passed on boot prompt
grep -q -i FORCEFSCK /proc/cmdline && forcefsck=-f

echo "*** Checking root file system ..."
FSCK_MAX_INST=1 fsck $forcefsck -a -C
status=$?

if test $status -gt 1
then
    if test $status -eq 32
    then
        echo "fsck(8) canceled by user request." 1>&2
    else
        if test $status -ge 4
        then
            echo "EXIT CODE = $status"                               1>&2
            echo ""                                                  1>&2
            echo "> A maintenance shell will be started for manual"  1>&2
            echo "> correction.  Refer to the file system-specific"  1>&2
            echo "> check utility and manual pages for correct it."  1>&2
            if type sulogin > /dev/null
            then
                sulogin
            else
                echo "Executing \`/bin/sh' as emergency shell ..."
                /bin/sh -
            fi
        fi
        echo "The system will be restarted now."
        umount -v -n -a -r
        mount -v -n -o remount,ro /
        halt -r;
        exit 99
    fi
fi
unset status

echo "*** Checking local file system(s) ..."
fsck $forcefsck -A -C -R -T -a

unset forcefsck

# Set system clock (2/2)

if test "${HWCLOCK:-UTC}" = UTC
then
    echo "(Startup) Setting system time from the hardware clock to UTC"
    hwclock --hctosys --utc
else
    echo "(Startup) The system time was already set to local time" 1>&2
fi

unset HWCLOCK

# Remount the root filesystem in *read-write mode*
echo "(Startup) Remounting root filesystem in read-write mode"
mount -v -n -o remount,rw /

# In modern distributions /etc/mtab is a symbolic link to /proc/mounts
rm -f /etc/mtab
ln -sf /proc/mounts /etc/mtab

echo "(Startup) Mounting local file systems [only]"
mount -a -t no,proc,sysfs,devtmpfs,shm,devpts,usbfs,cifs,smbfs,nfs

# Activate possible swap partitions or swap files

echo "(Startup) Activating swap devices, if any"
swapon -v -a

# Re-create hierarchy for temporary files (if needed)

if test ! -d /tmp
then
    mkdir /tmp
fi
if test ! -d /tmp/.font-unix
then
    mkdir /tmp/.font-unix
fi
if test ! -d /tmp/.ICE-unix
then
    mkdir /tmp/.ICE-unix
fi
if test ! -d /tmp/.X11-unix
then
    mkdir /tmp/.X11-unix
fi
chmod 1777 /tmp /tmp/.font-unix /tmp/.ICE-unix /tmp/.X11-unix

# Seek and destroy (some) temporary files

find /var/lock /var/run  \
 \( ! -type d -a ! -name utmp \) -exec rm -f '{}' +

# Set kernel parameters at runtime

echo "(Startup) Setting kernel parameters: sysctl -q --system"
sysctl -q --system

# Initialize the random number generator, see random(4)

echo "(Startup) Initializing random number generator"
echo "    /etc/random-seed <-> /dev/urandom ..."

if test -f /etc/random-seed
then
    cat /etc/random-seed > /dev/urandom
fi

# Read pool size from /proc or assign a default value
read -r < /proc/sys/kernel/random/poolsize size || size=4096

# Save seed file containing the whole entropy pool
dd if=/dev/urandom of=/etc/random-seed count=1 bs=${size} 2> /dev/null

chmod 600 /etc/random-seed
unset size

# Set host name and domain name for the system from /etc/rc.conf.
# This overrides any value given for sysctl(8)

echo "${HOSTNAME:-dragora}"        > /proc/sys/kernel/hostname
echo "${DOMAINNAME:-example.net}"  > /proc/sys/kernel/domainname

unset HOSTNAME DOMAINNAME

# Start the loopback device

echo "(Startup) Starting loopback device"

if type ip > /dev/null 2>&1
then
    ip addr del 127.0.0.1/8 dev lo 2> /dev/null
    ip addr add 127.0.0.1/8 dev lo brd + scope host
    ip link set lo up
elif type ifconfig > /dev/null 2>&1
then
    ifconfig lo up > /dev/null
else
    echo "Could not find ip(8) or ifconfig(1)." 1>&2
fi

# Update kernel modules

if test -f /lib/modules/"$(uname -r)"/modules.dep
then
    echo "(Startup) Refreshing kernel module list: depmod --quick"
    depmod --quick
else
    echo "(Startup) Generating kernel module dependency list: depmod --all"
    depmod --all
fi

# Configure ISA Plug-and-Play devices

if type isapnp > /dev/null 2>&1 -a type pnpdump > /dev/null 2>&1
then
    if test -f /etc/isapnp.conf
    then
        echo "(Startup) Setting ISA PnP devices using /etc/isapnp.conf"
        isapnp /etc/isapnp.conf
    else
        echo "(Startup) Creating resource information for ISA PnP devices"
        pnpdump > /etc/isapnp.conf

        echo "(Startup) Setting devices from the new /etc/isapnp.conf"
        isapnp /etc/isapnp.conf
    fi
fi

# Update the hardware database

echo "(Startup) Updating hardware database: udevadm hwdb --update"
udevadm hwdb --update

# Start to monitor services through perpd(8) instances

echo "(Startup) Monitoring services through perpd(8) instances"
if type perpboot > /dev/null
then
    udevadm control --exit;
    PERP_BASE=/etc/perp perpboot -d
fi

# Start ALSA (sound support)

if test -x /etc/rc.d/rc.alsa
then
    /etc/rc.d/rc.alsa start
fi

# Start user local instructions

if test -x /etc/rc.d/rc.local
then
    echo "(Startup) Running /etc/rc.d/rc.local"
    /etc/rc.d/rc.local
fi

# Load keyboard map from /etc/rc.conf

if test -n "$KEYMAP"
then
    loadkeys "$KEYMAP"
    unset KEYMAP
fi

# Set terminal attributes from /etc/rc.conf

# Screen blanking interval, default sets to 15 minutes
setterm -blank "${BLANKTIME:-15}"
unset BLANKTIME

